/** ****************************************************************************
* @addtogroup BSP
* @{
*******************************************************************************/

#ifndef __MCU_H
#define __MCU_H

#include "mcu_compliant.h"

#define MCU_SERIES_STM8

// STM8 系列 MCU 是 2 字节对齐
#define portBYTE_ALIGNMENT			2
#define portPOINTER_SIZE_TYPE		sizeof(void*)

#ifndef __BIG_ENDIAN__
	#define __BIG_ENDIAN__				0
#endif
#ifndef __LITTLE_ENDIAN__
	#define __LITTLE_ENDIAN__			1
#endif

#if (__LITTLE_ENDIAN__ == 1)
	// 网络字节顺序采用 big endian 排序方式
	// 所以如果 MCU 的字节序是 little endian 方式时，需要进行转换
	#define ntoh32(dw) 	BL32(dw)
	#define ntoh16(w) 	BL16(w)
	#define hton32(dw) 	BL32(dw)
	#define hton16(w) 	BL16(w)
#else
	#define ntoh32(dw) 	(dw)
	#define ntoh16(w) 	(w)
	#define hton32(dw) 	(dw)
	#define hton16(w) 	(w)
#endif

#if (defined __ICCSTM8__)
	#define ASM  asm
#else
	#error "Unsupported Compiler!"
#endif

#define INLINE	_Pragma("inline=forced")

/// NOP
#define NOP()   __no_operation()


//
// IO口操作宏定义
//
// GPIN Registers I/O
#define GPIN_DDR_CFG_Input(port, pin)			(port->DDR &= ~BV(pin))	// DDR=0: 表示输入模式
#define GPIN_DDR_CFG_Output(port, pin)			(port->DDR |= BV(pin))	// DDR=1: 表示输出模式

// Input Mode(DDR = 0):
#define GPIN_CR1_CFG_In_Floating(port, pin)		(port->CR1 &= ~BV(pin))	// CR1=0: Floating input
#define GPIN_CR1_CFG_In_PU(port, pin)			(port->CR1 |= BV(pin))	// CR1=1: Input with pull-up
// Output mode (DDR = 1):
#define GPIN_CR1_CFG_Out_OD(port, pin)			(port->CR1 &= ~BV(pin))	// CR1=0: Pseudo open drain
#define GPIN_CR1_CFG_Out_PP(port, pin)			(port->CR1 |= BV(pin))	// CR1=1: Push-pull

// Input Mode(DDR = 0):
#define GPIN_CR2_CFG_In_EXTI_Disable(port, pin)	(port->CR2 &= ~BV(pin))	// CR2=0: External interrupt disabled
#define GPIN_CR2_CFG_In_EXTI_Enable(port, pin)	(port->CR2 |= BV(pin))	// CR2=1: External interrupt enabled
// Output mode (DDR = 1):
#define GPIN_CR2_CFG_Out_Speed_2MHz(port, pin)	(port->CR2 &= ~BV(pin))	// CR2=0: Output speed up to 2 MHz
#define GPIN_CR2_CFG_Out_Speed_10MHz(port, pin)	(port->CR2 |= BV(pin))	// CR2=1: Output speed up to 10 MHz

// GPIN_CFG 可能的模式定义(共6种)
// bit[7..3]: unused
// bit[2]: DDR
// bit[1]: CR1
// bit[0]: CR2
#define GPIN_CFG_In_Floating	0x00
#define GPIN_CFG_In_PU			0x02

#define GPIN_CFG_Out_OD_2MHz	0x04
#define GPIN_CFG_Out_OD_10MHz	0x05
#define GPIN_CFG_Out_PP_2MHz	0x06
#define GPIN_CFG_Out_PP_10MHz	0x07

// GPIN APIs
void GPIN_Config(GPIO_TypeDef* port, uint8_t pin, uint8_t cfg);
#define GPIN_ConfigX(port, pin, cfg, x)			(GPIN_Config(port, pin, cfg), GPIN_WriteOut(port, pin, x))

// 原来的 API 不用了！用 GPIN_Config()/GPIN_ConfigX() 代替
//INLINE void GPIO_##NAME##_Init(GPIO_Mode_TypeDef mode)	{ GPIO_Init(GPIO##PORT, BV(PIN), mode); }

// 未使用的引脚默认配置
// 为了节能，对于未使用的 I/O 口，不能悬空(未连接/或高阻)，就必须配置为三种之一: 上拉输入、下拉输入、下拉输出
// 见《手册RM0031》P.119
#define GPIN_ConfigUnuseAs_IPU(port, pin) 					GPIN_Config(port, pin, GPIN_CFG_In_PU)
//#define GPIN_ConfigUnuseAs_IPD(port, pin) 				// 怎么配置成 IPD(下拉输入)???
#define GPIN_ConfigUnuseAs_Out_PP_Low(port, pin) 			GPIN_ConfigX(port, pin, GPIN_CFG_Out_PP_2MHz, RESET)
#define GPIO_Unuse(PORT, PIN) 								GPIN_ConfigUnuseAs_IPU(GPIO##PORT, PIN)

#define GPIN_ReadIn(port, pin)      						((port->IDR.All & BV(pin)) != 0)
#define GPIN_ReadOut(port, pin)								((port->ODR.All & BV(pin)) != 0)
#define GPIN_WriteOut(port, pin, x)							((x)?(port->ODR.All |= BV(pin)):(port->ODR.All &= ~BV(pin)))
#define GPIN_Toggle(port, pin)								(port->ODR.All ^= BV(pin))

// 命名的 GPIO APIs
#define GPIO_DEFINE(NAME, PORT, PIN) \
INLINE void GPIO_##NAME##_Config(uint8_t cfg)					{ GPIN_Config(GPIO##PORT, PIN, cfg); } \
INLINE void GPIO_##NAME##_ConfigX(uint8_t cfg, uint8_t x)				{ GPIN_ConfigX(GPIO##PORT, PIN, cfg, x); } \
INLINE void GPIO_##NAME##_Toggle()      					{ GPIN_Toggle(GPIO##PORT, PIN); } \
INLINE uint8_t   GPIO_##NAME##_ReadIn()      					{ return GPIN_ReadIn(GPIO##PORT, PIN); } \
INLINE uint8_t   GPIO_##NAME##_ReadOut()     					{ return GPIN_ReadOut(GPIO##PORT, PIN); } \
INLINE void GPIO_##NAME##_Out(uint8_t x)  						{ GPIN_WriteOut(GPIO##PORT, PIN, x); } \
INLINE uint8_t   GPIO_##NAME##_IntFlag()							{ static uint8_t old=0; uint8_t now=GPIN_ReadIn(GPIO##PORT, PIN); uint8_t flag=(old ^ now); old=now; return flag; } /*STM8S无中断标志位，只好通过静态变量来检查引脚状态是否有变化，来判断中断状态*/ \
INLINE void GPIO_##NAME##_IntClear()						{ /*STM8S无中断标志位需要清除！*/ } \
INLINE void GPIO_##NAME##_IntEnable(uint8_t trigger, uint8_t enable)	{ osCritical css; osCriticalEnter(css); (enable)?GPIN_CR2_CFG_In_EXTI_Enable(GPIO##PORT, PIN):GPIN_CR2_CFG_In_EXTI_Disable(GPIO##PORT, PIN); EXTI_SetExtIntSensitivity(EXTI_PORT_GPIO##PORT, (EXTI_Trigger_TypeDef)trigger); osCriticalLeave(css); } \
INLINE void GPIO_##NAME##_BidiConfig(uint8_t ci, uint8_t co, uint8_t io)	{ static uint8_t sci=0xFF,sco=0xFF,sio=0xF5; (sio==0xF5)?(sci=ci, sco=co):(0); (io==sio)?(0):(GPIO_##NAME##_Config((io==INPUT)?sci:sco), sio=io); } \
INLINE void GPIO_##NAME##_BidiSwitch(uint8_t io)					{ GPIO_##NAME##_BidiConfig(0, 0, io); } \
INLINE uint8_t   GPIO_##NAME##_BidiReadIn()						{ GPIO_##NAME##_BidiConfig(0, 0, INPUT); return GPIO_##NAME##_ReadIn(); } \
INLINE void GPIO_##NAME##_BidiOut(uint8_t x)  					{ GPIO_##NAME##_BidiConfig(0, 0, OUTPUT); GPIO_##NAME##_Out(x); }

#define GPIO_DEFINE_POLARITY(NAME, PORT, PIN, LEVEL) \
GPIO_DEFINE(NAME, PORT, PIN)\
INLINE void GPIO_##NAME##_On()          					{ GPIO_##NAME##_Out(LEVEL); } \
INLINE void GPIO_##NAME##_Off()         					{ GPIO_##NAME##_Out(!LEVEL); } \
INLINE void GPIO_##NAME##_Switch(uint8_t on)  					{ (!on == !LEVEL)?GPIO_##NAME##_Out(1):GPIO_##NAME##_Out(0); } \
INLINE uint8_t   GPIO_##NAME##_IsOutOn()     					{ return (GPIO_##NAME##_ReadOut() == LEVEL); } \
INLINE uint8_t   GPIO_##NAME##_IsOutOff()    					{ return (GPIO_##NAME##_ReadOut() != LEVEL); } \
INLINE uint8_t   GPIO_##NAME##_IsInOn()      					{ return (GPIO_##NAME##_ReadIn() == LEVEL); } \
INLINE uint8_t   GPIO_##NAME##_IsInOff()     					{ return (GPIO_##NAME##_ReadIn() != LEVEL); } \
INLINE uint8_t   GPIO_##NAME##_Polarity()      					{ return LEVEL; }

//
// 关于 Flash 的定义
//
#define FLASH_PAGE_SIZE FLASH_BLOCK_SIZE
//#define FLASH_PROGRAM_START_PHYSICAL_ADDRESS  0x8000
#define RAM_START_PHYSICAL_ADDRESS            	0x0000

//
// 关于中断向量表的定义
//
#define MCU_ENTRY		    FLASH_PROGRAM_START_PHYSICAL_ADDRESS
#define INTVEC_SIZE         0x80
#define OPCODE_INT_ADDR_EXT 0x8200

typedef struct stIntVectorItem {
	uint16_t code;   // = OPCODE_INT + ADDR_EXT
	uint16_t isr;    // = FUNC_void_voidp
} IntVectorItem;

/// 判断一个地址是否一个正确的程序入口地址（包括包括正确的 栈地址 和 中断向量表）
int isValidEntry(uint16_t entry);

/// 跳转到 Bootloader 中去执行(当前程序中止)
void jump2Entry(uint16_t entry);

// 系统重启：使用 WWDG (窗口看门狗)产生一个复位信号
#define systemReset()   WWDG_SWReset()

/// 是否是在进行调试
int isInDebugging();

/// 判断系统是否是异常启动
bool isAbnormalReboot();


#endif  // __MCU_H
/// @}
